<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>scatter</title>
        <script src="https://d3js.org/d3.v4.js"></script>
        <!-- <script type="text/javascript" src="../data/data.js"></script> -->
        <style>
			body {
				width: 100%;
				display: flex;
				margin: 0;
			}
			
			body .left{
				width: 28vw;
				height: 100%;
				padding-bottom: 20vh;
				overflow: auto;
				background-color: #69b3a2;
			}
			
			body .left .left-top{
				margin: 50px 30px 0 30px;
				padding-bottom: 5px;
				border-bottom: 1px solid #fff;
				font-size: 40px;
				font-weight: bold;
				color: #fff;
				user-select: none;
			}
			
			body .left .left-box1{
				margin: 20px 30px 0 30px;
				font-size: 14px;
				color: #fff;
				user-select: none;
			}
			
			body .left .left-box2{
				padding-bottom: 5px;
				border-bottom: 1px solid #fff;
				margin: 50px 30px 0 30px;
				font-size: 20px;
				font-weight: bold;
				color: #fff;
				user-select: none;
			}
			
			body .left .left-box3{
				margin: 20px 30px 0 30px;
				font-size: 14px;
				color: #fff;
				user-select: none;
			}
			
			body .right{
				position: fixed;
				left: 28vw;
				top: 0;
				overflow: hidden;
			}
			
            svg .handle {
                fill: #8a8b8e;
            }
            
            svg .selection {
                fill: #5a5b58;
                fill-opacity: 1;
                stroke: none;
            }
            .timeFliter{
                position: relative;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
                margin: auto;
                display: flex;
                justify-content: center;
                align-items: center;
                flex-direction:column;
            }
        </style>
    </head>
	
    <body>
        <div class="left">
			<div class="left-top">文献的可视化探索</div>
			<div class="left-box1">本项目是2022年秋季《可视语言与信息可视化（双语）》课程的结课项目，项目由智能与计算学部软件工程专业的郭以勒、闫瑞泽、范哲昊共同完成。</div>
			<div class="left-box2">成员信息</div>
			<ul class="left-box3">
				<li>郭以勒 3020209318</li>
				<li>闫瑞泽 3020001607</li>
				<li>范哲昊 3020244275</li>
			</ul>
			<div class="left-box2">功能指引</div>
			<ul class="left-box3">
				<li>实现了散点图的绘制，将每篇文章显示为一个节点</li>
				<li>实现了一个时间过滤器，当用户进行拖动时可选择一定的时间范围进行文献显示</li>
				<li>实现了一个透镜，用户点击页面，透镜即出现，透镜将跟随鼠标进行移动，方便用户查看某个区域所包含的关键词（透镜大小可调）</li>
				<li>实现了可视化交互，用户可快速感知各主题在空间中的分布</li>
			</ul>
		</div>
		
		<div class="right">
			<div id="my_dataviz"></div>
			
			<div class="timeFliter">
			    <label>From - To:&nbsp</label>
			    <div id="scale"></div>
			</div>
		</div>
        <script>
            // set the dimensions and margins of the graph
            var margin = {top: 10, right: 30, bottom: 30, left: 60},
                width = 900 - margin.left - margin.right,
                height = 900 - margin.top - margin.bottom;
				
			var flag_len = true;
			var res;
			var allRes = [];
            
            // append the svg object to the body of the page
            var svg = d3.select("#my_dataviz")
              .append("svg")
                .attr("width", width + margin.left * 2 + margin.right * 3)
                .attr("height", height - margin.bottom * 6.5);
				
            svg.append("g")
			  .attr('class', 'grah')
			  .attr('transform', `translate(${margin.left}, 0)`);
            
            //Read the data
            
            // Add X axis
            var x = d3.scaleLinear()
				.domain([-40, 40])
                .range([ 0, width - margin.right]);
            /*
              svg.append("g")
                .attr("transform", "translate(0," + height + ")")
                .call(d3.axisBottom(x));*/
            
            
            // Add Y axis
            var y = d3.scaleLinear()
                .domain([-35, 35])
                .range([ height - margin.bottom * 6, margin.top * 1.5]);
            /*
              svg.append("g")
                .call(d3.axisLeft(y));*/
				
			d3.csv("../data/data.csv", function(error, data){
				// console.log(data);
				
				// Add dots
				svg.select('.grah')
				.append('g')
				.attr('class', 'dots')
				.attr('transform', `translate(0, ${-5 * margin.top})`)
				    .selectAll(".showdot")
				    .data(data)
				    .enter()
				    .append("circle")
				      .attr("cx", function (d,i) { return x(d["x"]); } )
				      .attr("cy", function (d,i) { return y(d["y"]); } )
				      .attr("r", 1.5)
				      .style("fill", "#69b3a2")
				      .attr("class", 'showdot')
					  .attr('id', (d, i)=>"circle" + i)
				var topic = ["topic1","topic2","topic3","topic4","topic5","topic6","topic7","topic8"]
				
				// init();
				
				// 绘制话题选择区
				svg.append("g")
				    .attr("class","topicGroup")
					.attr('transform', `translate(${margin.left * 2}, ${margin.top * 8})`)
				    .selectAll(".topic")
				    .data(topic)
				    .enter()
				    .append("text")
				    .attr("x",width - 70)
				    .attr("y",function(d,i){
				        return 30*i
				    })
				    .attr("class","topic")
				    .text(function(d){
				        return d;
				    })
				    .attr("fill","grey")
					
				var selectTopic = [0,0,0,0,0,0,0,0]
				
				var highLight = function(){
				    svg.selectAll(".dot")
				    .transition()
				    .duration(1000)
				    .style("fill","#69b3a2")
				    for(var j = 0; j < data.length; ++j){
				        flag = 1
				        flag2 = 0
				        for(var z = 0; z < 8; ++z){
				            if(selectTopic[z] == 1){
				                flag2 = 1
				                if(!(data[j]["topic"+(z+1)] >= 0.3)){
				                    flag = 0;
				                    break;
				                }
				            }
				        }
				        if(flag == 1 && flag2 == 1){
				            svg.select("#circle" + j)
				                .transition()
				                .duration(500)
				                .style("fill","black")
				                .attr("r",4)
				                .transition()
				                .duration(500)
				                .attr("r",2)
				        }
				        
				    }
				}
				
				svg.selectAll(".topic")
				    .on("click",function(d,i){
						flag_len = false;
				        selectTopic[i] = (selectTopic[i] + 1) % 2;
				        if(selectTopic[i] == 1){
				            d3.select(this)
				                .style("fill","black")
								.attr('font-weight', 'bold')
				        }
				        else {
				            d3.select(this)
				                .style("fill","grey")
								.attr('font-weight', 500)
				        }
				        highLight();
				        svg.selectAll(".dot")
				            .attr("r",1.5)
				    })
				    
				// Add time fliter
				const tx = d3.scaleTime().domain([new Date(1980, 1, 1), new Date(2024, 1, 1) - 1]).range([0, width]);
				const txAxis = d3.axisBottom(tx);
				        
				const brush = d3.brushX()
				        .extent([[0, 0], [width, 5]])
				        .on("brush end", brushed);
				        
				const context = svg.select('.grah')
						.append("g")
				        .attr("class", "context")
				        .attr("transform", "translate(" + margin.left + "," + (height-margin.bottom * 8) + ")");
				        
				context.append("g")
				        .attr("class", "axis axis--tx")
				        .attr("transform", "translate(0," + 2 + ")")
				        .call(txAxis);
				        
				context.append("g")
				        .attr("class", "brush")
				        .call(brush)
				        .call(brush.move, [0,0]);
				
				function brushed() {
					flag_len = false;
					
				    const s = d3.event.selection || tx.range();
				    const timeSelection = s.map(tx.invert, tx);
				    const fromYear = +timeSelection[0].getFullYear();
				    const toYear = +timeSelection[1].getFullYear();
				    
				    document.getElementById('scale').innerHTML = fromYear + ' - ' + toYear;
				    svg.selectAll("circle")
				    .transition()
				    .duration(1000)
				    .style("fill","#69b3a2")
				    .attr('r', 1.5)
					.attr('opacity', 0)
					.attr('class', 'dot');
					
				    for(var j = 0; j < data.length; ++j){
				        if(+data[j]['year'] >= fromYear && +data[j]['year'] <= toYear){
				            res = svg.select("#circle" + j)
				                .transition()
				                .duration(500)
				                .style("fill","black")
				                .attr("r",4)
				                .transition()
				                .duration(500)
				                .attr("r",2)
								.attr('opacity', 1)
								.transition()
								.duration(1000)
								.style("fill","#69b3a2")
								.attr("class", 'showdot');
								
							// allRes.push(res);
				        }
				        
				    }
					
					// print();
				}
				
				// function print(){
				// 	console.log(allRes);
				// }
				
				function init(){
					svg.selectAll("circle")
					.transition()
					.duration(1000)
					.style("fill","#69b3a2")
					.attr('r', 1.5)
					.attr('opacity', 1);
				}
				
				
				// 设置透镜的初始位置
				var x_len = width / 2;
				var y_len = height / 2;
				
				// 设置透镜的初始比例
				var scale = 1;
				
				// 记录透镜半径
				var r;
				
				// 透镜放大缩小函数
				let zoom = d3.zoom()
						.scaleExtent([0.5, 1.6])
						.on('zoom', function(){
							zoomed(d3.event.transform);
						});
				
				// 透镜放大缩小函数
				function zoomed(transform){
					scale = transform.k;
					r = d3.select('.len')
						.attr('r');
					r = r * scale;
					// console.log(r * scale);
					d3.select('.len').attr('transform', `translate(${x_len}, ${y_len}) scale(${transform.k})`);
				};
				
				// 在svg画布内调用zoom
				d3.select('svg').call(zoom);
				
				var text_g;
				
				// 通过点击来调用透镜
				d3.select('svg').on('click', function(){
					// console.log('click');
					
					if (flag_len){
						d3.select(this)
						.append('g')
						.attr('class', 'len_g')
						.append('circle')
						.attr('class', 'len')
						.attr('fill', 'none')
						.attr('stroke', '#565656')
						.attr('stroke-width', 5)
						.attr('r', 40)
						.attr('transform', `translate(${width / 2}, ${height / 2})`);
						
						text_g = d3.select(this).select('.len_g')
								.append('g')
								.attr('class', 'text_g');
						
						flag_len = !flag_len;
					}
					else {
						d3.select('.len_g').remove();
						flag_len = !flag_len;
						reset();
					}
				});
				
				// 用于存储关键词
				var words = [];
				var allwords = [];
				
				// 存储并完成关键词分割
				for (let i = 0; i < data.length; i++){
					var word = data[i].text;
					words = word.split(',');
					// console.log(word);
					// console.log(words);
					data[i].words = words;
					// console.log(data[i].words);
					allwords.push(words);
					words = [];
				}
				
				// 计算点是否在透镜内
				function cal(dx, x, dy, y, r){
					// console.log('call');
					// console.log('dx:' + dx + " x:" + x + " dy:" + dy + " y:" + y + " r:" + r);
					return ((Math.sqrt(Math.pow(dx - x, 2) + Math.pow(dy - y, 2)) + 3) < r);
				}
				
				// console.log(allwords);
				
				// 绘制关键词
				function drawText(show, dx, dy, dr){
					var update = text_g.selectAll('.text-place')
								.data(show, d => d);
					
					var enter = update.enter();
					var exit = update.exit();
					
					enter.append('text')
							.attr('class', 'text-place')
							.attr('font-size', 10)
							.attr('font-weight', 'bold')
							.attr('fill', '#565656')
							// .attr('text-anchor', 'middle')
							.text(d => d)
							.attr('x', (d, i) => dx + dr * 2 + 10 + Math.floor(i / 10) * 100)
							.attr('y', (d, i) => dy + i * 20 - 10 - Math.floor(i / 10) * 200);
							
					update.text(d => d)
							.attr('x', (d, i) => dx + dr * 2 + 10 + Math.floor(i / 10) * 100)
							.attr('y', (d, i) => dy + i * 20 - 10 - Math.floor(i / 10) * 200);
							
					exit.remove();
				}
				
				function reset(){
					d3.selectAll('.showdot')
					.style('fill', '#69b3a2')
					.attr("r", 1.5);
					
					d3.selectAll('.dot')
					.style('fill', '#69b3a2')
					.attr("r", 1.5);
				};
				
				console.log(d3.selectAll('.dot'));
				
				// 设置交互，使透镜跟随鼠标位置移动
				d3.select('svg')
				.on('mousemove', function(d){
					x_len = d3.mouse(this)[0];
					y_len = d3.mouse(this)[1];
					
					// 初始恢复所有点为未选中状态
					if (!flag_len){
						if (y_len < 615)
						reset();
					}
					
					// console.log('x:' + x_len);
					// console.log('y:' + y_len);
					
					// 修改透镜的位置
					d3.select(this)
					.select('.len')
					.attr('transform', `translate(${x_len}, ${y_len}) scale(${scale})`);
					
					// 获取透镜半径
					r = d3.select(this)
						.select('.len')
						.attr('r');
					
					r = r * scale;
					
					// console.log(r);
					
					// 获取在透镜范围内的点
					var value = d3.selectAll('.showdot')
							.filter(d => {
								if (x(d.x) < x_len - margin.left - r || x(d.x) > x_len - margin.left + r || y(d.y) < y_len + margin.top * 5 - r || y(d.y) > y_len + margin.top * 5 + r)
									return false;
								else
									return cal(x(d.x), x_len - margin.left, y(d.y), y_len + margin.top * 5, r);
							})
							.style('fill', 'black')
							.attr("r", 2)
							.data();
					// var value = find(quadtree, x, y, r);
					
					// console.log(value.length);
					// console.log(value);
					
					var map = new Map();
					var show = [];
					// d3.select(this)
					// .select('.len_g')
					
					// 筛选关键词
					for (let i = 0; i < value.length; i++){
						for (let j = 0; j < value[i].words.length; j++){
							if (map.has(value[i].words[j])){
								var cnt = map.get(value[i].words[j]);
								cnt++;
								map.set(value[i].words[j], cnt);
							}
							else {
								map.set(value[i].words[j], 1);
							}
						}
					}
					
					var arrayObj = Array.from(map);
					// console.log(arrayObj);
					arrayObj.sort(function(a,b){return b[1] - a[1]});
					let cccc = 0;
					
					for (var [key, value] of arrayObj) {
						cccc++;
						if (cccc > arrayObj.length / 70){
							break;
						}
						// console.log(key + ' = ' + value);
						show.push(key);
					}
					
					// for (let [key, value] of map.entries()){
					// 	// console.log(value);
						
					// 	if (value >= 20) {
					// 		// console.log(key);
					// 		show.push(key);
					// 	}
					// }
					
					// // console.log(show);
					drawText(show, x_len - margin.left, y_len + margin.top * 5, r);
				});
				
			})
        </script>
    </body>
</html>